﻿using System;
using System.Collections.Generic;
using System.Linq;
using LiSA_Server.Base.AbstractActioners;
using LiSA_Server.Base.NHibernate;
using LiSA_Service.Reports.Dto.Queries;
using LiSA_Service.Reports.Helperclasses;
using LiSA_Service.ResearchProjects.Models;
using Environment = System.Environment;

namespace LiSA_Service.Reports.Actioners
{
    public class ReportActioner : BaseActioner
    {
        /// <summary>
        /// Generates a metadata report about a Project
        /// </summary>
        /// <param name="query">The query</param>
        /// <returns>A MetadataReportQueryResult</returns>
        public MetadataReportQueryResult CreateMetadataReport(MetadataReportQuery query)
        {
            var activeArticles = new List<Article>();
            var inactiveArticles = new List<Article>();
            // Find the project
            NHibernateProvider.Instance.WithSession(
               hsession =>
               {
                   var theProject = hsession.Get<ResearchProject>(query.ProjectID);

                   // Failsafe
                   if (theProject == null) return;
                   // Find the active articles
                   activeArticles.AddRange(theProject.Articles.Select(guid => hsession.Get<Article>(guid)));
                   // Find the inactive articles
                   inactiveArticles.AddRange(theProject.RemovedArticles.Select(guid => hsession.Get<Article>(guid)));
               });

            // Find each of the databases in all articles and count amount
            var activeDictionary = new Dictionary<string, int>();
            var inactiveDictionary = new Dictionary<string, int>();

            foreach (var article in activeArticles)
            {
                if (article.Database == null) article.Database = "Unknown Database";
                if (activeDictionary.ContainsKey(article.Database))
                {
                    activeDictionary[article.Database]++;
                }
                else
                {
                    activeDictionary.Add(article.Database, 1);
                }
            }

            foreach (var article in inactiveArticles)
            {
                if (article.Database == null) article.Database = "Unknown Database";
                if (inactiveDictionary.ContainsKey(article.Database))
                {
                    inactiveDictionary[article.Database]++;
                }
                else
                {
                    inactiveDictionary.Add(article.Database, 1);
                }
            }

            // Generate the report string
            // Note that this creates a X by Y grid with set values
            var theExport = new CsvExport();

            // Find all keys across dictionaries
            var allKeys = activeDictionary.Keys.ToList();
            allKeys.AddRange(inactiveDictionary.Keys.Where(key => !activeDictionary.ContainsKey(key)));

            // Add the key-value pair if existing in e*mach dictionary, otherwise add key,0
            theExport.AddRow();
            theExport["Article Status"] = "Accepted";
            foreach (var key in allKeys)
            {
                if (activeDictionary.ContainsKey(key))
                {
                    theExport[key] = activeDictionary[key];
                }
                else
                {
                    theExport[key] = "0";
                }
            }

            theExport.AddRow();
            theExport["Article Status"] = "Rejected";
            foreach (var key in allKeys)
            {
                if (inactiveDictionary.ContainsKey(key))
                {
                    theExport[key] = inactiveDictionary[key];
                }
                else
                {
                    theExport[key] = "0";
                }
            }

            return new MetadataReportQueryResult
            {
                CouldCreateReport = true,
                ReportAsString = theExport.Export(),
                // ReportFileAsBytes = theExport.ExportToBytes()
            };
        }

        /// <summary>
        /// Creates a .csv string that can be improted into a spreadsheet program and give the entire Projects representation oldskool style
        /// </summary>
        /// <param name="excelExportReportQuery">The query</param>
        /// <returns>A queryresult containing the .csv string for the report</returns>
        internal ExcelExportReportQueryResult CreateExcelExportReport(ExcelExportReportQuery query)
        {
            //First we need to get our information: Project, Articles for the project and all the feedback
            var activeArticles = new List<Article>();
            var inactiveArticles = new List<Article>();
            var theProject = new ResearchProject();
            var feedbacks = new List<ArticleFeedback>();
            var csvString = string.Empty;

            // Find the project
            NHibernateProvider.Instance.WithSession(
               hsession =>
               {
                   theProject = hsession.QueryOver<ResearchProject>().Where(x => x.ID == query.ProjectID)
                        .Fetch(x => x.Stages).Eager
                        .SingleOrDefault();
                   // Failsafe
                   if (theProject == null) return;
                   // Find the active articles
                   activeArticles.AddRange(theProject.Articles.Select(guid => hsession.Get<Article>(guid)));
                   // Find the inactive articles
                   inactiveArticles.AddRange(theProject.RemovedArticles.Select(guid => hsession.Get<Article>(guid)));
                   // Find the ArticleFeedback made for the project
                   var allfeedbacksforproject =
                       hsession.QueryOver<ArticleFeedback>().Where(x => x.ProjectID == theProject.ID);
                   if (allfeedbacksforproject != null && allfeedbacksforproject.List().Count > 0)
                   {
                       feedbacks.AddRange(allfeedbacksforproject.List());
                   }
                   //Now we need to build the .csv string
                   // Add columns for each Phase with empty columns to space correctly
                   csvString = csvString + ";;;;;;;";
                   foreach (var projectStage in theProject.Stages.Where(x => x.Stage > 0))
                   {
                       csvString = csvString + projectStage.Description + " - Recommendation";
                       foreach (var decisionpoint in projectStage.DecisionPoints)
                       {
                           csvString = csvString + ";";
                       }
                   }
                   // Columns done, nextline
                   csvString = csvString + Environment.NewLine;
                   // Add default columns
                   csvString = csvString + "UniqueID;Title;Authors;Year;Keyword and Tags;Source or Venue;Database or Publisher;";

                   // Add decisiopoint columns, skipping Stage 0 as we're only showing information for Accepted articles
                   foreach (var projectStage in theProject.Stages.Where(x => x.Stage > 0))
                   {
                       foreach (var stage in projectStage.DecisionPoints)
                       {
                           csvString = csvString + stage + ";";
                       }
                   }

               });
            // Columns done, nextline
            csvString = csvString + Environment.NewLine;
            var uniqueID = 1;
            // Now we need to iterate through the articles, insert relevant information as well as a "1" in the DecisionPoint columns selected
            foreach (var article in activeArticles)
            {
                if (article.KeyWords == null) article.KeyWords = string.Empty;
                if (article.Title == null) article.Title = string.Empty;
                // Standard info
                csvString = csvString + uniqueID + ";" + article.Title.Replace(";", ",") + ";" + article.Author + ";" + article.PublicationDate + ";" + article.KeyWords.Replace(";", ",") + ";" + article.Organization + ";" + article.Database + ";";
                uniqueID++;

                // Fill out colums for projectstages. Skip stage 0(accepted/rejected)
                foreach (var projectStage in theProject.Stages.Where(x => x.Stage > 0))
                {
                    foreach (var decisionpoint in projectStage.DecisionPoints)
                    {
                        if (feedbacks.Any() && feedbacks.Any(x => x.ArticleID == article.ID) && feedbacks.Any(x => String.Equals(x.OptionSelected.Trim(), decisionpoint.Trim(), StringComparison.CurrentCultureIgnoreCase)))
                        {
                            var totalFeedbackForArticleStageAndOption = feedbacks.Count(x => x.ArticleID == article.ID &&
                                                                                                x.Stage == projectStage.Stage &&
                                                                                                String.Equals(x.OptionSelected.Trim(), decisionpoint.Trim(), StringComparison.CurrentCultureIgnoreCase));

                            csvString = csvString + totalFeedbackForArticleStageAndOption;
                        }
                        csvString = csvString + ";";
                    }
                }
                csvString = csvString + Environment.NewLine;
            }
            // And we're done. Built result and return
            return new ExcelExportReportQueryResult { TotalResults = 1, CouldCreateReport = true, ReportAsString = csvString };
        }
    }
}